﻿using System;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using O1.Kernel.Primitives;

namespace Tests.O1.Kernel.Primitives
{
    [TestClass]
    public class Int64PropertyTests
    {
        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyWritesDataIntoPackedSizeBufferAsExpected()
        {
            var subject = new Int64Property(6, 122);
            var buffer = new byte[Int64Property.Size];
            subject.Write(buffer, 0);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyWritesDataValuesAsExpected()
        {
            var subject = new Int64Property(99, 12200);
            var buffer = new byte[Int64Property.Size];
            subject.Write(buffer, 0);

            var actualValue = BitConverter.ToInt64(buffer, 0);
            var actualKey = BitConverter.ToInt32(buffer, 8);

            actualValue.Should().Be(12200);
            actualKey.Should().Be(99);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyReadsAsExpected()
        {
            var buffer = new byte[Int64Property.Size];
            var data = BitConverter.GetBytes(678000999L);
            var key = BitConverter.GetBytes(77);

            Array.Copy(data, buffer, 8);
            Array.Copy(key, 0, buffer, 8, 4);

            var subject = Int64Property.Read(buffer, 0);
            subject.Key.Should().Be(77);
            subject.Value.Should().Be(678000999L);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyWritesThenReadsAsExpected()
        {
            var expected = new Int64Property(99, 12200);
            var buffer = new byte[Int64Property.Size];
            expected.Write(buffer, 0);

            var actual = Int64Property.Read(buffer, 0);
            actual.Key.Should().Be(expected.Key);
            actual.Value.Should().Be(expected.Value);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyEqualityIsKeyValueEquality()
        {
            var subject1 = new Int64Property(99, 12200);
            var subject2 = new Int64Property(99, 12200);
            (subject1 == subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyInequalityIsKeyInequality()
        {
            var subject1 = new Int64Property(99, 12200);
            var subject2 = new Int64Property(98, 12200);
            (subject1 != subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyInequalityIsValueInequality()
        {
            var subject1 = new Int64Property(98, 124500);
            var subject2 = new Int64Property(98, 12200);
            (subject1 != subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyEqualsIsValueEquality()
        {
            var subject1 = new Int64Property(99, 12200);
            var subject2 = new Int64Property(99, 12200);
            subject1.Equals(subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyEqualsIsKeyInequality()
        {
            var subject1 = new Int64Property(99, 12200);
            var subject2 = new Int64Property(98, 12200);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyEqualsIsValueInequality()
        {
            var subject1 = new Int64Property(98, 124500);
            var subject2 = new Int64Property(98, 12200);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyIsNotEqualToNull()
        {
            object other = null;
            new Int64Property(98, 124500).Equals(other).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyGetHashCodeIsConsistent()
        {
            var subject = new Int64Property(98, 124500);
            subject.GetHashCode().Should().Be(subject.GetHashCode());   
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyGetHashCodeIsDifferentForDifferentKey()
        {
            var subject1 = new Int64Property(98, 124500);
            var subject2 = new Int64Property(101, 124500);
            subject1.GetHashCode().Should().NotBe(subject2.GetHashCode());
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyGetHashCodeIsDifferentForDifferentValue()
        {
            var subject1 = new Int64Property(101, 124500);
            var subject2 = new Int64Property(101, 1200);
            subject1.GetHashCode().Should().NotBe(subject2.GetHashCode());
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyGetHashCodeIsDifferentForDifferentKeyAndValue()
        {
            var subject1 = new Int64Property(88, 124500);
            var subject2 = new Int64Property(101, 1200);
            subject1.GetHashCode().Should().NotBe(subject2.GetHashCode());
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyObjectEqualsIsEquality()
        {
            var subject1 = new Int64Property(98, 124500);
            object subject2 = new Int64Property(98, 124500);
            subject1.Equals(subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyObjectEqualsIsInequalityForDifferentKey()
        {
            var subject1 = new Int64Property(99, 124500);
            object subject2 = new Int64Property(98, 124500);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyObjectEqualsIsInequalityForDifferentValue()
        {
            var subject1 = new Int64Property(99, 124500);
            object subject2 = new Int64Property(99, 500);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyObjectEqualsIsInequalityForDifferentKeyAndValue()
        {
            var subject1 = new Int64Property(8769, 124500);
            object subject2 = new Int64Property(99, 500);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void Int64PropertyObjectEqualsIsInequalityForDifferentType()
        {
            var subject1 = new Int64Property(99, 124500);
            object subject2 = new object();
            subject1.Equals(subject2).Should().BeFalse();
        }
    }
}
